package ca.unbc.cpsc672.fuzzy.function;

import java.util.HashMap;
import java.util.LinkedList;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;

import ca.unbc.cpsc672.GUIUtils;
import ca.unbc.cpsc672.fuzzy.FuzzySet;
import ca.unbc.cpsc672.fuzzy.IOUtils;

/**
 * One membership function
 * 
 * @author xi
 * 
 */
public abstract class MembershipFunction {
	private final String label;

	private HashMap<String, Double> paraValMap = new HashMap<>();
	private HashMap<String, Text> paraTextMap = new HashMap<>();
	private LinkedList<String> paraNameList = new LinkedList<>();
	private FuzzySet fuzzySet;
	private double concentrate = 1;

	public MembershipFunction(String label) {
		this.label = label;
	}

	public FuzzySet getFuzzySet() {
		return fuzzySet;
	}

	public void setFuzzySet(FuzzySet fuzzySet) {
		this.fuzzySet = fuzzySet;
	}

	public String getLinguisticVariable() {
		return label;
	}

	/**
	 * Build UI for parameters modification
	 * 
	 * @param parent
	 * @return
	 */
	public Composite buildUI(Composite parent) {
		Composite composite = new Composite(parent, SWT.NONE);
		composite.setLayout(new GridLayout(2, false));
		composite.setLayoutData(GUIUtils.buildGridData());

		final Image img = new Image(parent.getDisplay(),
				MembershipFunction.class.getResourceAsStream(getImageName()));

		Canvas canvas = new Canvas(composite, SWT.NONE);
		GridData data = GUIUtils.buildGridData();
		data.horizontalSpan = 2;
		data.heightHint = img.getImageData().height + 20;

		canvas.setLayoutData(data);
		canvas.addPaintListener(new PaintListener() {

			@Override
			public void paintControl(PaintEvent e) {
				e.gc.drawImage(img, 0, 0);
			}

		});

		for (String pName : paraNameList) {
			Text txt = buidTextBox(composite, pName);
			String pVal = String.valueOf(paraValMap.get(pName));
			txt.setText(pVal);
			paraTextMap.put(pName, txt);
		}
		return composite;
	}

	protected void addParamenter(String pName, double pVal) {
		paraNameList.add(pName);
		paraValMap.put(pName, pVal);
	}

	protected double getParamenter(String pName) {
		return paraValMap.get(pName);
	}

	private Text buidTextBox(Composite c, final String labelName) {
		Label lbl1 = new Label(c, SWT.NONE);
		lbl1.setText(labelName);

		final Text txt = new Text(c, SWT.RIGHT);
		txt.addModifyListener(new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e) {
				String str = txt.getText();
				paraValMap.put(labelName, new Double(str));
			}

		});
		GridData data = new GridData();
		data.widthHint = 40;
		txt.setLayoutData(data);
		return txt;
	}

	/**
	 * Get the function output for an input crisp value
	 * 
	 * @param x
	 * @return
	 */
	public double calcProperbility(double x) {
		double f = calcFunction(x);
		// concentration
		return Math.pow(f, concentrate);
	}

	public String toCSVString() {
		StringBuffer sb = new StringBuffer();
		sb.append(label).append(",");
		sb.append(IOUtils.getTypeString(this)).append(",");
		for (String para : paraNameList) {
			double val = paraValMap.get(para);
			sb.append(String.valueOf(val)).append(",");
		}
		return sb.toString();
	}

	public void setConsentrate(double v) {
		concentrate = v;
	}

	public String getFullName() {
		return fuzzySet.getName() + "." + label;
	}

	public abstract double getCenter();

	protected abstract String getImageName();

	protected abstract double calcFunction(double x);
}
